<!--
Google IO 2012/2013 HTML5 Slide Template

Authors: Eric Bidelman <ebidel@gmail.com>
         Luke Mahé <lukem@google.com>

URL: https://code.google.com/p/io-2012-slides
-->
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="chrome=1">
  <!--<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">-->
  <!--<meta name="viewport" content="width=device-width, initial-scale=1.0">-->
  <!--This one seems to work all the time, but really small on ipad-->
  <!--<meta name="viewport" content="initial-scale=0.4">-->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <link rel="stylesheet" media="all" href="theme/css/default.css">
  <link rel="stylesheet" media="only screen and (max-device-width: 480px)" href="theme/css/phone.css">
  <base target="_blank"> <!-- This amazingness opens all links in a new tab. -->
  <script data-main="js/slides" src="js/require-1.0.8.min.js"></script>
</head>
<body style="opacity: 0">

<slides class="layout-widescreen">

  <slide class="logoslide nobackground">
    <article class="flexbox vcenter">
      <span><img src="images/google_developers_logo.png"></span>
    </article>
  </slide>

  <slide class="title-slide segue nobackground">
    <aside class="gdbar"><img src="images/google_developers_icon_128.png"></aside>
    <!-- The content of this hgroup is replaced programmatically through the slide_config.json. -->
    <hgroup class="auto-fadein">
      <h1 data-config-title><!-- populated from slide_config.json --></h1>
      <h2 data-config-subtitle><!-- populated from slide_config.json --></h2>
      <p data-config-presenter><!-- populated from slide_config.json --></p>
    </hgroup>
  </slide>

    <slide>
    <hgroup>
      <h2>About the speaker</h2>
    </hgroup>
    <article>
      <ul>
        <li>Hi! I'm Ikai Lan
          <ul>
            <li>I live and work in New York City, NY</li>
            <li>Currently: YouTube developer relations</li>
            <li>Formerly: Google Apps, Google Cloud</li>
          </ul>
        </li>
        <li>This presentation: <a href="http://yt-mobile-codelab.appspot.com">http://yt-mobile-codelab.appspot.com</a></li>
        <li>All the contents of this codelab: <a href="https://code.google.com/p/youtube-mobile-codelab/">https://code.google.com/p/youtube-mobile-codelab</a></li>
      </ul>
    </article>
  </slide>

  <slide hidden>
    <hgroup>
      <h2>Teaching Assistants</h2>
    </hgroup>
    <article>
      <ul>
        <li>?</li>
        <li>?</li>
        <li>?</li>
        <li>?</li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>Today we will have hands on experience</h2>
    </hgroup>
    <article>
      <ul>
        <li>Registering API keys and API access</li>
        <li>Building a mobile app making API calls to YouTube
          <ul>
            <li>Integrating YouTube Search with the Topics API</li>
            <li>Authenticating using Google Play services</li>
            <li>Adding videos to playlists</li>
          </ul>
        </li>
        <li>Making use of YouTube SDK to play videos</li>
        <li>Having fun!</li>
      </ul>
    </article>
  </slide>

  <!-- TODO Insert slide showing initial product and final service -->

  <slide>
    <hgroup>
      <h2>You will need ...</h2>
    </hgroup>
    <article>
      <ul>
        <li>Android phone running 4.0+</li>
        <li>Laptop running the Android SDK and IDE</li>
        <li>USB cable to push to your Android device</li>
      </ul>
    </article>
  </slide>  

   <slide>
    <hgroup>
      <h2>Android SDK: http://developer.android.com/sdk</h2>
    </hgroup>
    <article class="flexbox vcenter">
      <img src="images/sdk-cube.png" alt="Android SDK" title="Download the Android SDK">
      <footer class="source">http://developer.android.com/sdk/index.html</footer>
    </article>
  </slide>

  <!-- Download the code TODO add these slides-->
  <slide>
    <hgroup>
      <h2>Download the starter app and these slides</h2>
    </hgroup>
    <article>
      <ul>
        <li><a href="http://code.google.com/p/youtube-mobile-codelab">http://code.google.com/p/youtube-mobile-codelab</a></li>
        <li>Unzip this to a location of your choice</li>
      </ul>
    </article>
  </slide>    

  <!-- Import the code -->
  <slide>
    <hgroup>
      <h2>Import the code into your IDE</h2>
    </hgroup>
    <article>
      <ul>
        <li>In Eclipse
          <ul>
            <li>File->Import</li>
            <li>Android->Existing Android Code Into Workspace</li>
            <li>Let it import in the background. When it is ready, run it</li>
          </ul>
        </li>
      </ul>
    </article>
  </slide>   

  <!-- Build the code to make sure there are no issues -->
  <slide>
    <hgroup>
      <h2>Build the code and push to devices</h2>
    </hgroup>
    <article>
      <ul>
        <li>If needed from command line: "adb devices"</li>
        <li>Push to device</li>
      </ul>
      <img src="images/dummy-04.png" width="200px" alt="Topic search" title="Topic search">      
      <img src="images/dummy-03.png" width="200px" alt="Topic search results" title="Topic search results">      
      <img src="images/dummy-02.png" width="200px" alt="Video search results" title="Video search results">      
      <img src="images/dummy-01.png" width="200px" alt="Video playback" title="Video playback">
    </article>
  </slide>  

  <!-- Time for code -->
  <slide class="segue dark nobackground">
    <aside class="gdbar"><img src="images/google_developers_icon_128.png"></aside>
    <hgroup class="auto-fadein">
      <h2>Coding time!</h2>
      <h3>Time for us to add the code to make this work!</h3>
    </hgroup>
  </slide>

  <!-- TODO Architecture of the app and what we will do -->

  <!-- Register a simple API key -->
  <slide>
    <hgroup>
      <h2>Code we will write (5 steps)</h2>
    </hgroup>
    <article>
      <ul>
        <li>Search Topics API for a topic</li>
        <li>Search YouTube for videos with that topic</li>
        <li>Use Play Services on your phone to get an authentication token for API calls</li>
        <li>Find the user's playlist uses the authentication token</li>
        <li>Add ability for user to add videos to playlist using the authentication token</li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>Getting a developer key (Simple API access)</h2>
    </hgroup>
    <article>
      <ul>
        <li>
          Two kinds of API access:
          <ul>
            <li>Simple - don't need to "act" as a user</li>
            <li>Client ID (OAuth) - need to do things a user can only do while logged in</li>
          </ul>
        </li>
      </ul>
      <ul>
        <li>Browse to <a href="http://code.google.com/apis/console">http://code.google.com/apis/console</a></li>
        <li>Click "API access"</li>
        <li>Scroll to the section labeled "Simple API Access"
          <img src="images/simple-api-access.png" alt="Simple API access" title="Register a simple API access key">
        </li>
      </ul>

    </article>
  </slide>  

  <!-- Topics API -->
  <slide>
    <hgroup>
      <h2>Find topics</h2>
    </hgroup>
    <article>
      <ul>
        <li>Make API calls to the Freebase API to find a "topic"</li>
        <li>A "topic" is more precise than a string - Python (programming) vs Python (snake)</li>
        <li>Steps:
          <ul>
            <li>Call the API via HTTP</li>
            <li>Parse out the "mid" parameter from JSON response</li>
            <li>Start a new activity with this "mid" to find videos (already done)</li>
          </ul>
        </li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>SearchFragment.java</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // FetchTopicsTask#doInBackground
      try {
          // Call the Topics API and fetch a list of mids
          URL url = new URL(FREEBASE_URL + params[0]);
          URLConnection c = url.openConnection();

          // Parse JSON using Jackson
          ObjectMapper o = new ObjectMapper();
          JsonNode rootNode = o.readTree(c.getInputStream());
          ArrayNode results = (ArrayNode) rootNode.get("result");

          for(JsonNode result : results) {
              Topic topic = new Topic();
              topic.setDisplayName(result.get("name").asText());
              topic.setMid(result.get("mid").asText());
              topics.add(topic);
          }
      } catch (MalformedURLException e) {
      } catch (IOException e) {
          Log.e(TAG, "Got IOException " + e);
      }
</pre>
    </article>
  </slide>

  <!-- Search API -->
  <slide>
    <hgroup>
      <h2>YouTube's search API</h2>
    </hgroup>
    <article>
      <ul>
        <li>Uses the "mid" parameter from the first step to find videos</li>
        <li>Steps:</li>
        <li>
          <ul>
            <li>Instantiate the YouTube API client (simple)</li>
            <li>Instantiate a YouTube search request object</li>
            <li>Pass the search request object to the client</li>
            <li>Convert the response into a list of results</li>
          </ul>
        </li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>SearchResultActivity.java (Part 1)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // CallYouTubeAPITask#doInBackGround()
      String apiKey = getResources().getString(R.string.api_key);

      HttpTransport httpTransport = new NetHttpTransport();
      JsonFactory jsonFactory = new JacksonFactory();

      YouTube yt = new YouTube.Builder(httpTransport, jsonFactory, new HttpRequestInitializer() {
          @Override
          public void initialize(HttpRequest httpRequest) throws IOException {
          }
      }).setApplicationName("YouTubeMobileCodeLab/0.1")
              .build();
</pre>
    </article>
  </slide>  

  <slide>
    <hgroup>
      <h2>SearchResultActivity.java (Part 2)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // CallYouTubeAPITask#doInBackGround()
      try {
          SearchListResponse response = yt.search().list("id,snippet")
                  .setKey(apiKey)
                  .setTopicId(mids[0])
                  .setType("video")
                  .setFields("items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)")
                  .setMaxResults(25l)
                  .execute();

          List&lt;SearchResult&gt; results = response.getItems();
          for(SearchResult result : results) {
              VideoInfo info = new VideoInfo();
              info.setId(result.getId().getVideoId());
              info.setTitle(result.getSnippet().getTitle());
              info.setDescription(result.getSnippet().getDescription());
              info.setThumbnailUrl(result.getSnippet().getThumbnails().get("default").getUrl());
              videos.add(info);
          }
      } catch (IOException e) {
          Log.e(TAG, "Got IOException: " + e);
      }
</pre>
    </article>
  </slide>  

  <!-- Adding authentication -->
  <slide>
    <hgroup>
      <h2>Adding pieces that require user authentication</h2>
    </hgroup>
    <article>
      <ul>
        <li>We do this anything we act on behalf of a user:</li>
        <ul>
          <li>Upload videos</li>
          <li>Manage videos, playlists or channels</li>
          <li>View a user's private videos</li>
        </ul>
        <li>Steps:</li>
        <li>
          <ul>
            <li>Register a client application</li>
            <li>Use Google Play Services to ask the user for permission</li>
            <li>Save the auth token (already completed)</li>
          </ul>
        </li>
      </ul>
    </article>
  </slide>  

  <!-- Register a certificate -->
  <slide>
    <hgroup>
      <h2>Adding a certificate</h2>
    </hgroup>
    <article>
      <ul>
        <li>Browse to <a href="http://code.google.com/apis/console">http://code.google.com/apis/console</a></li>
        <li>Click "API access"</li>
        <li>Click "Create another client ID"</li>
        <li>Select "Installed Application" and "Android" for the type</li>
        <li>Enter a package name and signing certificate (SHA1)</li>
        <li>Click "Create client ID" to save this information</li>
        <li>More info: <a href="https://developers.google.com/+/mobile/android/getting-started">https://developers.google.com/+/mobile/android/getting-started</a></li>
      </ul>
    </article>
  </slide>  

   <slide>
    <hgroup>
      <h2>Adding a certificate</h2>
    </hgroup>
    <article class="flexbox vcenter">
      <img src="images/register-api-certificate.png" height="80%" alt="Google API console" title="Register an API certificate">
      <footer class="source">http://code.google.com/apis/console</footer>
    </article>
  </slide>

  <!-- Add sign in with Play Services -->
  <slide>
    <hgroup>
      <h2>SessionManager.java</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // FetchTokenTask#doInBackground()
      try {
          String authToken = GoogleAuthUtil.getToken(mContext,
                  accountName, "oauth2:" + YouTubeScopes.YOUTUBE + " "
                  + YouTubeScopes.YOUTUBE_UPLOAD);

          AccountAuth auth = new AccountAuth();
          auth.setAccountName(accountName);
          auth.setToken(authToken);
          return auth;
      } catch (UserRecoverableAuthException e) {
          Intent authIntent = e.getIntent();
          authIntent.putExtra(AccountManager.KEY_ACCOUNT_NAME, accountName);

          ((Activity) mContext).startActivityForResult(authIntent, 
            SessionManager.REQUEST_USER_AUTHORIZATION);
      } catch (IOException e) {
          Log.e(TAG, "Got IOException:" + e.getMessage());
      } catch (GoogleAuthException e) {
          Log.e(TAG, "Got GoogleAuthException:" + e.getMessage());
      }
      return null;
</pre>
    </article>
  </slide>  

  <!-- YouTube API calls to fetch playlist -->
  <slide>
    <hgroup>
      <h2>Find the user's playlists</h2>
    </hgroup>
    <article>
      <ul>
        <li>Create a YouTube API client that takes a client ID</li>
        <li>Make API call and return playlist items</li>
        <li>Render playlists in custom view</li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>PlaylistFragment.java</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // FetchPlaylistTask#doInBackground()
      GoogleCredential credential = new GoogleCredential();
      credential.setAccessToken(authToken);

      HttpTransport httpTransport = new NetHttpTransport();
      JsonFactory jsonFactory = new JacksonFactory();

      YouTube yt = new YouTube.Builder(httpTransport, jsonFactory,
              credential).setApplicationName("YouTubeMobileCodeLab/0.1")
              .build();

      try {
          PlaylistListResponse response = yt.playlists()
                  .list("id,snippet").setMine(true).execute();
          return response.getItems();
      } catch (IOException e) {
          if (e.getMessage().startsWith("401")) { // Not the cleanest
              GoogleAuthUtil.invalidateToken(getActivity(), authToken);
          }
      }
      return null;
      </pre>
    </article>
  </slide>  

  <!-- YouTube API calls to add to a playlist -->
  <slide>
    <hgroup>
      <h2>Add video to playlist</h2>
    </hgroup>
    <article>
      <ul>
        <li>Create a YouTube API client that takes a client ID</li>
        <li>See if a playlist with the topic name exists
          <ul>
            <li>If not, create one</li>
            <li>If so, find it and we'll use that playlist</li>
          </ul>
        </li>
        <li>To create a playlist, we need to specify: name, description, privacy</li>
        <li>Add the video to the playlist, we need to create a Snippet and Resource, then make a playlist update API call</li>
      </ul>
    </article>
  </slide>

  <slide>
    <hgroup>
      <h2>VideoPlayerActivity.java (Part 1)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      // AddToPlaylistTask#doInBackground()
      GoogleCredential credential = new GoogleCredential();
      credential.setAccessToken(authToken);

      HttpTransport httpTransport = new NetHttpTransport();
      JsonFactory jsonFactory = new JacksonFactory();

      YouTube yt = new YouTube.Builder(httpTransport, jsonFactory,
              credential).setApplicationName("YouTubeMobileCodeLab/0.1")
              .build();
</pre>
    </article>
  </slide>  

  <slide>
    <hgroup>
      <h2>VideoPlayerActivity.java (Part 2)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
      try {
          publishProgress("Checking to see if playlist exists ...");

          PlaylistListResponse playlistResponse = yt.playlists().list("id,snippet")
                  .setMaxResults(50l)
                  .setMine(true)
                  .setFields("items(id,snippet/title)")
                  .execute();

          Playlist playlist = null;
          for (Playlist playlistItem : playlistResponse.getItems()) {
              if (playlistItem.getSnippet().getTitle().equals(generatedPlaylistName)) {
                  publishProgress("Playlist exists already");
                  playlist = playlistItem;
              }
          }
</pre>
    </article>
  </slide>  

  <slide>
    <hgroup>
      <h2>VideoPlayerActivity.java (Part 3)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
          // Still inside the "try" block
          if (playlist == null) {
              publishProgress("Playlist does not exist. Creating ... ");

              // Create the playlist snippet
              PlaylistSnippet playlistSnippet = new PlaylistSnippet();
              playlistSnippet.setTitle(generatedPlaylistName);
              playlistSnippet.setDescription(getResources().getString(R.string.autogenerated_playlist_about)
                      + ": " + mTopicName);

              // Here we set the privacy status to private since we don't want to share these
              PlaylistStatus playlistStatus = new PlaylistStatus();
              playlistStatus.setPrivacyStatus(PUBLIC);

              // Instantiate a new playlist and give it the two attributes
              playlist = new Playlist();
              playlist.setSnippet(playlistSnippet);
              playlist.setStatus(playlistStatus);

              // make the API call
              playlist = yt.playlists()
                      .insert("snippet,status", playlist)
                      .execute();
          }
</pre>
    </article>
  </slide>  

  <slide>
    <hgroup>
      <h2>VideoPlayerActivity.java (Part 4)</h2>
    </hgroup>
    <article class="smaller">
      <pre class="prettyprint" data-lang="java">
                // Still inside the "try" block
                ResourceId resourceId = new ResourceId();
                resourceId.setKind(YOUTUBE_VIDEO);
                resourceId.setVideoId(mVideoId);

                PlaylistItemSnippet playlistItemSnippet = new PlaylistItemSnippet();
                playlistItemSnippet.setTitle(mVideoTitle);
                playlistItemSnippet.setPlaylistId(playlist.getId());
                playlistItemSnippet.setResourceId(resourceId);

                PlaylistItem playlistItem = new PlaylistItem();
                playlistItem.setSnippet(playlistItemSnippet);

                publishProgress("Adding video to playlist ...");
                PlaylistItem itemInsertResponse =  yt.playlistItems()
                        .insert("snippet,contentDetails", playlistItem)
                        .execute();
                return itemInsertResponse;
            } catch (IOException e) {
                Log.e(TAG, "Got IO exception: " + e);
            }
</pre>
    </article>
  </slide>  



  <!-- You're done! Free exploration. Link to docs -->
  <slide>
    <hgroup>
      <h2>You're done! Time for free exploration</h2>
    </hgroup>
    <article>
      <ul>
        <li>YouTube API docs: 
          <ul>
            <li>Data API: <a href="https://developers.google.com/youtube/v3/">https://developers.google.com/youtube/v3</a></li>
            <li>Android Player API: <a href="https://developers.google.com/youtube/android/player/">https://developers.google.com/youtube/android/player</a></li>
          </ul>
        </li>
        <li>Google Play Services: <a href="http://developer.android.com/google/play-services">http://developer.android.com/google/play-services</a></li>
      </ul>
    </article>
  </slide>  

  <slide class="thank-you-slide segue nobackground">
    <aside class="gdbar right"><img src="images/google_developers_icon_128.png"></aside>
    <article class="flexbox vleft auto-fadein">
      <h2>&lt;Thank You!&gt;</h2>
      <p>Ikai Lan: ikai@google.com</p>
    </article>
    <p class="auto-fadein" data-config-contact>
      <!-- populated from slide_config.json -->
    </p>
  </slide>

  <slide class="logoslide dark nobackground">
    <article class="flexbox vcenter">
      <span><img src="images/google_developers_logo_white.png"></span>
    </article>
  </slide>

  <slide class="backdrop"></slide>

</slides>

<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_trackPageview']);

(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>

<!--[if IE]>
  <script src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script>
  <script>CFInstall.check({mode: 'overlay'});</script>
<![endif]-->
</body>
</html>
